/*
//
//              INTEL CORPORATION PROPRIETARY INFORMATION
//  This software is supplied under the terms of a license  agreement or
//  nondisclosure agreement with Intel Corporation and may not be copied
//  or disclosed except in  accordance  with the terms of that agreement.
//    Copyright (c) 2007-2008 Intel Corporation. All Rights Reserved.
//
//
*/

#include "umc_defs.h"
#if defined(UMC_ENABLE_AVS_VIDEO_DECODER)

#include "umc_avs_dec_decompressor.h"
#include "umc_avs_pic.h"

namespace UMC
{

static
IppiSize AVSLumaBlockSize[4] =
{
    {16, 16}, {16, 8}, {8, 16}, {8, 8}
};

void AVSDecompressor::CompensateMotionLumaPMacroBlock(void)
{
    // set pointer to the block's beginning
    m_lumaMCParams.pDst[0] = m_recCtx.m_pPlanes8u[0];
    m_lumaMCParams.dstStep = m_recCtx.m_iPitch;

    // set the initial block position
    m_lumaMCParams.pointBlockPos.x = m_recCtx.MbX * 16;
    m_lumaMCParams.pointBlockPos.y = m_recCtx.MbY * 16;

    // select block size
    m_lumaMCParams.sizeBlock = AVSLumaBlockSize[m_pMbInfo->divType];

    switch (m_pMbInfo->divType)
    {
    case Div_16x16:
        CompensateMotionLumaUniDir(0, PredForward);
        break;

    case Div_16x8:
        CompensateMotionLumaUniDir(0, PredForward);

        m_lumaMCParams.pointBlockPos.y += 8;
        m_lumaMCParams.pDst[0] += m_lumaMCParams.dstStep * 8;
        CompensateMotionLumaUniDir(2, PredForward);
        break;

    case Div_8x16:
        CompensateMotionLumaUniDir(0, PredForward);

        m_lumaMCParams.pointBlockPos.x += 8;
        m_lumaMCParams.pDst[0] += 8;
        CompensateMotionLumaUniDir(1, PredForward);
        break;

    default:
        CompensateMotionLumaUniDir(0, PredForward);

        m_lumaMCParams.pointBlockPos.x += 8;
        m_lumaMCParams.pDst[0] += 8;
        CompensateMotionLumaUniDir(1, PredForward);

        m_lumaMCParams.pointBlockPos.x -= 8;
        m_lumaMCParams.pointBlockPos.y += 8;
        m_lumaMCParams.pDst[0] += m_lumaMCParams.dstStep * 8 - 8;
        CompensateMotionLumaUniDir(2, PredForward);

        m_lumaMCParams.pointBlockPos.x += 8;
        m_lumaMCParams.pDst[0] += 8;
        CompensateMotionLumaUniDir(3, PredForward);
        break;
    }

} // void AVSDecompressor::CompensateMotionLumaPMacroBlock(void)

#define COMPENSATE_MOTION_LUMA(block_num) \
{ \
    eAVSPredType predType; \
    predType = (eAVSPredType) m_pMbInfo->predType[block_num]; \
    if (PredBiDir == predType) \
    { \
        CompensateMotionLumaBiDir(block_num); \
    } \
    else \
    { \
        CompensateMotionLumaUniDir(block_num, predType); \
    } \
}

void AVSDecompressor::CompensateMotionLumaBMacroBlock(void)
{
    // set pointer to the block's beginning
    m_lumaMCParams.pDst[0] = m_recCtx.m_pPlanes8u[0];
    m_lumaMCParams.dstStep = m_recCtx.m_iPitch;

    // set the initial block position
    m_lumaMCParams.pointBlockPos.x = m_recCtx.MbX * 16;
    m_lumaMCParams.pointBlockPos.y = m_recCtx.MbY * 16;

    // select block size
    m_lumaMCParams.sizeBlock = AVSLumaBlockSize[m_pMbInfo->divType];

    switch (m_pMbInfo->divType)
    {
    case Div_16x16:
        COMPENSATE_MOTION_LUMA(0)
        break;

    case Div_16x8:
        COMPENSATE_MOTION_LUMA(0)

        m_lumaMCParams.pointBlockPos.y += 8;
        m_lumaMCParams.pDst[0] += m_lumaMCParams.dstStep * 8;
        COMPENSATE_MOTION_LUMA(2)
        break;

    case Div_8x16:
        COMPENSATE_MOTION_LUMA(0)

        m_lumaMCParams.pointBlockPos.x += 8;
        m_lumaMCParams.pDst[0] += 8;
        COMPENSATE_MOTION_LUMA(1)
        break;

    default:
        COMPENSATE_MOTION_LUMA(0)

        m_lumaMCParams.pointBlockPos.x += 8;
        m_lumaMCParams.pDst[0] += 8;
        COMPENSATE_MOTION_LUMA(1)

        m_lumaMCParams.pointBlockPos.x -= 8;
        m_lumaMCParams.pointBlockPos.y += 8;
        m_lumaMCParams.pDst[0] += m_lumaMCParams.dstStep * 8 - 8;
        COMPENSATE_MOTION_LUMA(2)

        m_lumaMCParams.pointBlockPos.x += 8;
        m_lumaMCParams.pDst[0] += 8;
        COMPENSATE_MOTION_LUMA(3)
        break;
    }

} // void AVSDecompressor::CompensateMotionLumaBMacroBlock(void)

void AVSDecompressor::CompensateMotionLumaUniDir(Ipp32s blockNum, eAVSPredType typePred)
{
    Ipp32s refIdx;

    // set the source
    {
        AVSPicture *pRef;

        refIdx = m_pMbInfo->refIdx[typePred - 1][blockNum];
        pRef = m_pRefs[typePred - 1][refIdx];
        m_lumaMCParams.pSrc[0] = pRef->m_pPlanes8u[0];
        m_lumaMCParams.srcStep = pRef->m_iPitch;
    }

    // set the vector
    m_lumaMCParams.pointVector = m_pMbInfo->mv[typePred - 1][blockNum];

    // do compensation
    ippiInterpolateLumaBlock_AVS_8u_P1R(&m_lumaMCParams);

    // do weighting
    if (m_pMbInfo->weighting_prediction)
    {
        Ipp32s luma_scale, luma_shift;

        // get weighting parameters
        luma_scale = m_recCtx.m_pSlcHeader->luma_scale[typePred - 1][refIdx];
        luma_shift = m_recCtx.m_pSlcHeader->luma_shift[typePred - 1][refIdx];

        ippiWeightPrediction_AVS_8u_C1R(m_lumaMCParams.pDst[0],
                                        m_lumaMCParams.dstStep,
                                        m_lumaMCParams.pDst[0],
                                        m_lumaMCParams.dstStep,
                                        luma_scale,
                                        luma_shift,
                                        m_lumaMCParams.sizeBlock);
    }

} // void AVSDecompressor::CompensateMotionLumaUniDir(Ipp32s blockNum, eAVSPredType typePred)

void AVSDecompressor::CompensateMotionLumaBiDir(Ipp32s blockNum)
{
    Ipp8u tempBlock[16 * 16 + 16];
    Ipp8u *pFrw, *pBck;
    Ipp32s stepFrw, stepBck;

    //
    // do forward motion compensation
    //

    // zero motion vector - simple reset pointers
    if (0 == m_pMbInfo->mv[AVS_FORWARD][blockNum].scalar)
    {
        Ipp32s refIdx;
        AVSPicture *pRef;

        refIdx = m_pMbInfo->refIdx[AVS_FORWARD][blockNum];
        pRef = m_pRefs[AVS_FORWARD][refIdx];
        pFrw = pRef->m_pPlanes8u[0];
        stepFrw = pRef->m_iPitch;

        // calculate offset to a corresponding place in the reference picture
        pFrw += m_lumaMCParams.pDst[0] - m_pPlanes8u[0];

        // do weighting
        if (m_pMbInfo->weighting_prediction)
        {
            Ipp32s luma_scale, luma_shift;

            // get weighting parameters
            luma_scale = m_recCtx.m_pSlcHeader->luma_scale[AVS_FORWARD][refIdx];
            luma_shift = m_recCtx.m_pSlcHeader->luma_shift[AVS_FORWARD][refIdx];

            ippiWeightPrediction_AVS_8u_C1R(pFrw,
                                            stepFrw,
                                            m_lumaMCParams.pDst[0],
                                            m_lumaMCParams.dstStep,
                                            luma_scale,
                                            luma_shift,
                                            m_lumaMCParams.sizeBlock);

            // set the pointer to the block
            pFrw = m_lumaMCParams.pDst[0];
            stepFrw = m_lumaMCParams.dstStep;
        }
    }
    // doing honest compensation
    else
    {
        pFrw = m_lumaMCParams.pDst[0];
        stepFrw = m_lumaMCParams.dstStep;
        CompensateMotionLumaUniDir(blockNum, PredForward);
    }

    //
    // do backward motion compensation
    //

    // zero motion vector - simple reset pointers
    if (0 == m_pMbInfo->mv[AVS_BACKWARD][blockNum].scalar)
    {
        Ipp32s refIdx;
        AVSPicture *pRef;

        refIdx = m_pMbInfo->refIdx[AVS_BACKWARD][blockNum];
        pRef = m_pRefs[AVS_BACKWARD][refIdx];
        pBck = pRef->m_pPlanes8u[0];
        stepBck = pRef->m_iPitch;

        // calculate offset to a corresponding place in the reference picture
        pBck += m_lumaMCParams.pDst[0] - m_pPlanes8u[0];

        // do weighting
        if (m_pMbInfo->weighting_prediction)
        {
            Ipp32s luma_scale, luma_shift;

            // get weighting parameters
            luma_scale = m_recCtx.m_pSlcHeader->luma_scale[AVS_BACKWARD][refIdx];
            luma_shift = m_recCtx.m_pSlcHeader->luma_shift[AVS_BACKWARD][refIdx];

            ippiWeightPrediction_AVS_8u_C1R(pBck,
                                            stepBck,
                                            align_pointer<Ipp8u *> (tempBlock, 16),
                                            16,
                                            luma_scale,
                                            luma_shift,
                                            m_lumaMCParams.sizeBlock);

            // set the pointer to the block
            pBck = align_pointer<Ipp8u *> (tempBlock, 16);
            stepBck = 16;
        }
    }
    // doing honest compensation
    else
    {
        Ipp8u *pDstPrev;
        Ipp32s stepPrev;

        // change the destination pointer
        pDstPrev = m_lumaMCParams.pDst[0];
        stepPrev = m_lumaMCParams.dstStep;
        m_lumaMCParams.pDst[0] = align_pointer<Ipp8u *> (tempBlock, 16);
        m_lumaMCParams.dstStep = 16;

        pBck = m_lumaMCParams.pDst[0];
        stepBck = m_lumaMCParams.dstStep;
        CompensateMotionLumaUniDir(blockNum, PredBackward);

        // restore the destination pointer
        m_lumaMCParams.pDst[0] = pDstPrev;
        m_lumaMCParams.dstStep = stepPrev;
    }

    // get average from two directions
    ippiInterpolateBlock_H264_8u_P3P1R(pFrw,
                                       pBck,
                                       m_lumaMCParams.pDst[0],
                                       m_lumaMCParams.sizeBlock.width,
                                       m_lumaMCParams.sizeBlock.height,
                                       stepFrw,
                                       stepBck,
                                       m_lumaMCParams.dstStep);


} // void AVSDecompressor::CompensateMotionLumaBiDir(Ipp32s blockNum)

static
IppiSize AVSChromaBlockSize[2][4] =
{
    // 4:2:0 block sizes
    {
        {8, 8}, {8, 4}, {4, 8}, {4, 4}
    },

    // 4:2:2 block sizes
    {
        {8, 16}, {8, 8}, {4, 16}, {4, 8}
    }
};

void AVSDecompressor::CompensateMotionChromaPMacroBlock(void)
{
    Ipp32s blockHeight;

    // set pointer to the block's beginning
    m_chromaMCParams.pDst[0] = m_recCtx.m_pPlanes8u[1];
    m_chromaMCParams.pDst[1] = m_recCtx.m_pPlanes8u[2];
    m_chromaMCParams.dstStep = m_recCtx.m_iPitch;

    // set the initial block position
    m_chromaMCParams.pointBlockPos.x = m_recCtx.MbX * 8;
    m_chromaMCParams.pointBlockPos.y = m_recCtx.MbY * 8;

    // select block size
    m_chromaMCParams.sizeBlock = AVSChromaBlockSize[m_recCtx.m_pSeqHeader->chroma_format - 1]
                                                   [m_pMbInfo->divType];
    blockHeight = m_chromaMCParams.sizeBlock.height;

    switch (m_pMbInfo->divType)
    {
    case Div_16x16:
        CompensateMotionChromaUniDir(0, PredForward);
        break;

    case Div_16x8:
        CompensateMotionChromaUniDir(0, PredForward);

        m_chromaMCParams.pointBlockPos.y += blockHeight;
        m_chromaMCParams.pDst[0] += m_chromaMCParams.dstStep * blockHeight;
        m_chromaMCParams.pDst[1] += m_chromaMCParams.dstStep * blockHeight;
        CompensateMotionChromaUniDir(2, PredForward);
        break;

    case Div_8x16:
        CompensateMotionChromaUniDir(0, PredForward);

        m_chromaMCParams.pointBlockPos.x += 4;
        m_chromaMCParams.pDst[0] += 4;
        m_chromaMCParams.pDst[1] += 4;
        CompensateMotionChromaUniDir(1, PredForward);
        break;

    default:
        CompensateMotionChromaUniDir(0, PredForward);

        m_chromaMCParams.pointBlockPos.x += 4;
        m_chromaMCParams.pDst[0] += 4;
        m_chromaMCParams.pDst[1] += 4;
        CompensateMotionChromaUniDir(1, PredForward);

        m_chromaMCParams.pointBlockPos.x -= 4;
        m_chromaMCParams.pointBlockPos.y += blockHeight;
        m_chromaMCParams.pDst[0] += m_chromaMCParams.dstStep * blockHeight - 4;
        m_chromaMCParams.pDst[1] += m_chromaMCParams.dstStep * blockHeight - 4;
        CompensateMotionChromaUniDir(2, PredForward);

        m_chromaMCParams.pointBlockPos.x += 4;
        m_chromaMCParams.pDst[0] += 4;
        m_chromaMCParams.pDst[1] += 4;
        CompensateMotionChromaUniDir(3, PredForward);
        break;
    }

} // void AVSDecompressor::CompensateMotionChromaPMacroBlock(void)

#define COMPENSATE_MOTION_CHROMA(block_num) \
{ \
    eAVSPredType predType; \
    predType = (eAVSPredType) m_pMbInfo->predType[block_num]; \
    if (PredBiDir == predType) \
    { \
        CompensateMotionChromaBiDir(block_num); \
    } \
    else \
    { \
        CompensateMotionChromaUniDir(block_num, predType); \
    } \
}

void AVSDecompressor::CompensateMotionChromaBMacroBlock(void)
{
    Ipp32s blockHeight;

    // set pointer to the block's beginning
    m_chromaMCParams.pDst[0] = m_recCtx.m_pPlanes8u[1];
    m_chromaMCParams.pDst[1] = m_recCtx.m_pPlanes8u[2];
    m_chromaMCParams.dstStep = m_recCtx.m_iPitch;

    // set the initial block position
    m_chromaMCParams.pointBlockPos.x = m_recCtx.MbX * 8;
    m_chromaMCParams.pointBlockPos.y = m_recCtx.MbY * 8;

    // select block size
    m_chromaMCParams.sizeBlock = AVSChromaBlockSize[m_recCtx.m_pSeqHeader->chroma_format - 1]
                                                   [m_pMbInfo->divType];
    blockHeight = m_chromaMCParams.sizeBlock.height;

    switch (m_pMbInfo->divType)
    {
    case Div_16x16:
        COMPENSATE_MOTION_CHROMA(0);
        break;

    case Div_16x8:
        COMPENSATE_MOTION_CHROMA(0);

        m_chromaMCParams.pointBlockPos.y += blockHeight;
        m_chromaMCParams.pDst[0] += m_chromaMCParams.dstStep * blockHeight;
        m_chromaMCParams.pDst[1] += m_chromaMCParams.dstStep * blockHeight;
        COMPENSATE_MOTION_CHROMA(2);
        break;

    case Div_8x16:
        COMPENSATE_MOTION_CHROMA(0);

        m_chromaMCParams.pointBlockPos.x += 4;
        m_chromaMCParams.pDst[0] += 4;
        m_chromaMCParams.pDst[1] += 4;
        COMPENSATE_MOTION_CHROMA(1);
        break;

    default:
        COMPENSATE_MOTION_CHROMA(0);

        m_chromaMCParams.pointBlockPos.x += 4;
        m_chromaMCParams.pDst[0] += 4;
        m_chromaMCParams.pDst[1] += 4;
        COMPENSATE_MOTION_CHROMA(1);

        m_chromaMCParams.pointBlockPos.x -= 4;
        m_chromaMCParams.pointBlockPos.y += blockHeight;
        m_chromaMCParams.pDst[0] += m_chromaMCParams.dstStep * blockHeight - 4;
        m_chromaMCParams.pDst[1] += m_chromaMCParams.dstStep * blockHeight - 4;
        COMPENSATE_MOTION_CHROMA(2);

        m_chromaMCParams.pointBlockPos.x += 4;
        m_chromaMCParams.pDst[0] += 4;
        m_chromaMCParams.pDst[1] += 4;
        COMPENSATE_MOTION_CHROMA(3);
        break;
    }

} // void AVSDecompressor::CompensateMotionChromaBMacroBlock(void)

#define ippiInterpolateChromaBlock_AVS_8u_P2R \
    ippiInterpolateChromaBlock_H264_8u_P2R

void AVSDecompressor::CompensateMotionChromaUniDir(Ipp32s blockNum, eAVSPredType typePred)
{
    Ipp32s refIdx;

    // set the source
    {
        AVSPicture *pRef;

        refIdx = m_pMbInfo->refIdx[typePred - 1][blockNum];
        pRef = m_pRefs[typePred - 1][refIdx];
        m_chromaMCParams.pSrc[0] = pRef->m_pPlanes8u[1];
        m_chromaMCParams.pSrc[1] = pRef->m_pPlanes8u[2];
        m_chromaMCParams.srcStep = pRef->m_iPitch;
    }

    // set the vector
    m_chromaMCParams.pointVector = m_pMbInfo->mv[typePred - 1][blockNum];

    // do compensation
    ippiInterpolateChromaBlock_AVS_8u_P2R(&m_chromaMCParams);

    // do weighting
    if (m_pMbInfo->weighting_prediction)
    {
        Ipp32s chroma_scale, chroma_shift;

        // get weighting parameters
        chroma_scale = m_recCtx.m_pSlcHeader->chroma_scale[typePred - 1][refIdx];
        chroma_shift = m_recCtx.m_pSlcHeader->chroma_shift[typePred - 1][refIdx];

        ippiWeightPrediction_AVS_8u_C1R(m_chromaMCParams.pDst[0],
                                        m_chromaMCParams.dstStep,
                                        m_chromaMCParams.pDst[0],
                                        m_chromaMCParams.dstStep,
                                        chroma_scale,
                                        chroma_shift,
                                        m_chromaMCParams.sizeBlock);
        ippiWeightPrediction_AVS_8u_C1R(m_chromaMCParams.pDst[1],
                                        m_chromaMCParams.dstStep,
                                        m_chromaMCParams.pDst[1],
                                        m_chromaMCParams.dstStep,
                                        chroma_scale,
                                        chroma_shift,
                                        m_chromaMCParams.sizeBlock);
    }

} // void AVSDecompressor::CompensateMotionChromaUniDir(Ipp32s blockNum, eAVSPredType typePred)

void AVSDecompressor::CompensateMotionChromaBiDir(Ipp32s blockNum)
{
    Ipp8u tempBlock[16 * 16 + 16];
    Ipp8u *(pFrw[2]), *(pBck[2]);
    Ipp32s stepFrw, stepBck;

    //
    // do forward motion compensation
    //

    // zero motion vector - simple reset pointers
    if (0 == m_pMbInfo->mv[AVS_FORWARD][blockNum].scalar)
    {
        Ipp32s refIdx;
        AVSPicture *pRef;

        refIdx = m_pMbInfo->refIdx[AVS_FORWARD][blockNum];
        pRef = m_pRefs[AVS_FORWARD][refIdx];
        pFrw[0] = pRef->m_pPlanes8u[1];
        pFrw[1] = pRef->m_pPlanes8u[2];
        stepFrw = pRef->m_iPitch;

        // calculate offset to a corresponding place in the reference picture
        pFrw[0] += m_chromaMCParams.pDst[0] - m_pPlanes8u[1];
        pFrw[1] += m_chromaMCParams.pDst[1] - m_pPlanes8u[2];

        // do weighting
        if (m_pMbInfo->weighting_prediction)
        {
            Ipp32s chroma_scale, chroma_shift;

            // get weighting parameters
            chroma_scale = m_recCtx.m_pSlcHeader->chroma_scale[AVS_FORWARD][refIdx];
            chroma_shift = m_recCtx.m_pSlcHeader->chroma_shift[AVS_FORWARD][refIdx];

            ippiWeightPrediction_AVS_8u_C1R(pFrw[0],
                                            stepFrw,
                                            m_chromaMCParams.pDst[0],
                                            m_chromaMCParams.dstStep,
                                            chroma_scale,
                                            chroma_shift,
                                            m_chromaMCParams.sizeBlock);
            ippiWeightPrediction_AVS_8u_C1R(pFrw[1],
                                            stepFrw,
                                            m_chromaMCParams.pDst[1],
                                            m_chromaMCParams.dstStep,
                                            chroma_scale,
                                            chroma_shift,
                                            m_chromaMCParams.sizeBlock);

            // set the pointers to the blocks
            pFrw[0] = m_chromaMCParams.pDst[0];
            pFrw[1] = m_chromaMCParams.pDst[1];
            stepFrw = m_chromaMCParams.dstStep;
        }
    }
    // doing honest compensation
    else
    {
        pFrw[0] = m_chromaMCParams.pDst[0];
        pFrw[1] = m_chromaMCParams.pDst[1];
        stepFrw = m_chromaMCParams.dstStep;
        CompensateMotionChromaUniDir(blockNum, PredForward);
    }

    //
    // do backward motion compensation
    //

    // zero motion vector - simple reset pointers
    if (0 == m_pMbInfo->mv[AVS_BACKWARD][blockNum].scalar)
    {
        Ipp32s refIdx;
        AVSPicture *pRef;

        refIdx = m_pMbInfo->refIdx[AVS_BACKWARD][blockNum];
        pRef = m_pRefs[AVS_BACKWARD][refIdx];
        pBck[0] = pRef->m_pPlanes8u[1];
        pBck[1] = pRef->m_pPlanes8u[2];
        stepBck = pRef->m_iPitch;

        // calculate offset to a corresponding place in the reference picture
        pBck[0] += m_chromaMCParams.pDst[0] - m_pPlanes8u[1];
        pBck[1] += m_chromaMCParams.pDst[1] - m_pPlanes8u[2];

        // do weighting
        if (m_pMbInfo->weighting_prediction)
        {
            Ipp32s chroma_scale, chroma_shift;

            // get weighting parameters
            chroma_scale = m_recCtx.m_pSlcHeader->chroma_scale[AVS_BACKWARD][refIdx];
            chroma_shift = m_recCtx.m_pSlcHeader->chroma_shift[AVS_BACKWARD][refIdx];

            ippiWeightPrediction_AVS_8u_C1R(pBck[0],
                                            stepBck,
                                            align_pointer<Ipp8u *> (tempBlock, 16),
                                            16,
                                            chroma_scale,
                                            chroma_shift,
                                            m_chromaMCParams.sizeBlock);
            ippiWeightPrediction_AVS_8u_C1R(pBck[1],
                                            stepBck,
                                            align_pointer<Ipp8u *> (tempBlock, 16) + 8,
                                            16,
                                            chroma_scale,
                                            chroma_shift,
                                            m_chromaMCParams.sizeBlock);

            // set the pointers to the blocks
            pBck[0] = align_pointer<Ipp8u *> (tempBlock, 16);
            pBck[1] = align_pointer<Ipp8u *> (tempBlock, 16) + 8;
            stepBck = 16;
        }
    }
    // doing honest compensation
    else
    {
        Ipp8u *(pDstPrev[2]);
        Ipp32s stepPrev;

        // change the destination pointer
        pDstPrev[0] = m_chromaMCParams.pDst[0];
        pDstPrev[1] = m_chromaMCParams.pDst[1];
        stepPrev = m_chromaMCParams.dstStep;
        m_chromaMCParams.pDst[0] = align_pointer<Ipp8u *> (tempBlock, 16);
        m_chromaMCParams.pDst[1] = align_pointer<Ipp8u *> (tempBlock, 16) + 8;
        m_chromaMCParams.dstStep = 16;

        pBck[0] = m_chromaMCParams.pDst[0];
        pBck[1] = m_chromaMCParams.pDst[1];
        stepBck = m_chromaMCParams.dstStep;
        CompensateMotionChromaUniDir(blockNum, PredBackward);

        // restore the destination pointer
        m_chromaMCParams.pDst[0] = pDstPrev[0];
        m_chromaMCParams.pDst[1] = pDstPrev[1];
        m_chromaMCParams.dstStep = stepPrev;
    }

    // get average from two directions
    ippiInterpolateBlock_H264_8u_P3P1R(pFrw[0],
                                       pBck[0],
                                       m_chromaMCParams.pDst[0],
                                       m_chromaMCParams.sizeBlock.width,
                                       m_chromaMCParams.sizeBlock.height,
                                       stepFrw,
                                       stepBck,
                                       m_chromaMCParams.dstStep);
    ippiInterpolateBlock_H264_8u_P3P1R(pFrw[1],
                                       pBck[1],
                                       m_chromaMCParams.pDst[1],
                                       m_chromaMCParams.sizeBlock.width,
                                       m_chromaMCParams.sizeBlock.height,
                                       stepFrw,
                                       stepBck,
                                       m_chromaMCParams.dstStep);


} // void AVSDecompressor::CompensateMotionChromaBiDir(Ipp32s blockNum)

} // namespace UMC

#endif // defined(UMC_ENABLE_AVS_VIDEO_DECODER)
